package com.ws.client;

import com.alibaba.fastjson.JSONObject;
import com.ws.client.other.InputSave;
import com.ws.client.other.VBean;
import com.ws.client.other.WinClientBean;
import com.ws.client.utils.FileUtils;
import com.ws.client.utils.LocalStorageUtils;
import com.ws.client.utils.LogHelper;
import com.ws.client.utils.RandomStringGenerator;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Date;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;

public class SeleniumHandler {

    private static ChromeDriver getNewChromeDriver() {

        ChromeOptions options = new ChromeOptions();
        //无头指定

//        String tmpdir = System.getProperty("java.io.tmpdir").concat("Selenium\\").concat(RandomStringGenerator.generateRandomString(15).toUpperCase());
//        FileUtils.makeDir(tmpdir);
//        LogHelper.debug(tmpdir);
//        options.addArguments("--user-data-dir=" + tmpdir);
//        options.addArguments("--headless");

        //移除报错提示
        //options.addArguments("--allowed-ips");
        //options.addArguments("--single-process");
        //"                      –single-process"
        // options.addArguments("--start-minimized"); //无效
        options.addArguments("--no-zygote");
        options.addArguments("--whitelisted-ips=\"\"");
        options.addArguments("blink-settings=imagesEnabled=false"); //禁止加图片,如果爬取图片的话,这个不能禁用
        options.addArguments("--disable-images");//进行显示图片
        options.addArguments("--disable-gpu"); // 谷歌文档提到需要加上这个属性来规避bug
        options.addArguments("--disable-software-rasterizer"); //禁用3D软件光栅化器
        options.addArguments("--no-sandbox");// 为了让linux root用户也能执行
        // 优化参数
        options.addArguments("--disable-dev-shm-usage"); //解决在某些VM环境中，/dev/shm分区太小，导致Chrome失败或崩溃
        options.addArguments("--disable-plugins"); //禁用插件,加快速度
        options.addArguments("--disable-extensions"); //禁用扩展
        options.addArguments("--disable-popup-blocking"); //关闭弹窗拦截
        options.addArguments("--ignore-certificate-errors"); //  禁现窗口最大化
        options.addArguments("--allow-running-insecure-content");  //关闭https提示 32位
        options.addArguments("--mute-audio");//静音
        ChromeDriver chromeDriver = new ChromeDriver(options);
        chromeDriver.get("https://web.whatsapp.com");
        return chromeDriver;
    }

    public static void automatePhone(String pid, String phone) {
        try {
            WinClientBean winClientBean = InputSave.chromeDriverConcurrentHashMap.get(pid);
            if (winClientBean == null) {
                return;
            }
            ChromeDriver chromeDriver = winClientBean.getChromeDriver();
            WebDriverWait wait = new WebDriverWait(chromeDriver, InputSave.wait_time);
            WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input.selectable-text")));
            element.click();
            //clear 手机输入里的
            Actions actions = new Actions(chromeDriver);
            actions.keyDown(Keys.CONTROL).sendKeys("a").keyUp(Keys.CONTROL);
            actions.sendKeys(Keys.DELETE);
            actions.perform();
            //填写手机号码
            element.sendKeys(phone);
            Thread.sleep(300);

            //x889kno x1a8lsjc xbbxn1n xxbr6pl x1n2onr6 x1rg5ohu xk50ysn x1f6kntn xyesn5m x1z11no5 xjy5m1g x1mnwbp6 x4pb5v6 x1i1c1dq x87ea8o x196p5u9 x1t2x6vz x1hl8ikr xfagghw x9dyr19 x9lcvmn xbtce8p x14v0smp xo8ufso xcjl5na x1k3x3db xuxw1ft xv52azi
            //element = element.findElement(By.xpath("//div[@class='_1M6AF _3QJHf']"));
            //获取验证码按钮
            element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("button.xbtce8p")));
            //element = element.findElement(By.cssSelector("button.xbtce8p"));
            if (element == null) {
                LogHelper.debug("未找到下一步按钮,请联系管理员!!!");
            }
            element.click();
            Thread.sleep(300);
            try {
                element = chromeDriver.findElementById("link-device-phone-number-entry-screen-error");
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("pid", pid);
                InputSave.baseWebsocketClient.sendToServer("phoneError", jsonObject);
                LogHelper.debug(pid + "|号码输入格式错误:" + phone);
                InputSave.closeWin(pid);
                return;
            } catch (Exception ex) {

            }
            LogHelper.debug(pid + "|号码格式验证通过:" + phone);
            //link-device-phone-number-entry-screen-error

            // 等待元素可见并获取其属性值
            String verifyCode = "";
            while (true) {
                try {
                    //查找验证码
                    element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@aria-details='link-device-phone-number-code-screen-instructions']")));
                    String code = element.getAttribute("data-link-code");
                    code = code.replaceAll(",", "");
                    if (!verifyCode.equals(code)) {
                        verifyCode = code;
                        LogHelper.debug("验证码更新:" + verifyCode);
                        //InputSave.baseWebsocketClient.send(new VBean(verifyCode.replace("-", ""), "phone", uuid, phone).toString());

                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put("pid", pid);
                        jsonObject.put("code", code);
                        InputSave.baseWebsocketClient.sendToServer("upPhoneCode", jsonObject);
                    }
                    Thread.sleep(2000);
                    //检查是否已登录
                    if (timeoutCheck(pid, chromeDriver)) {
                        return;
                    }
                } catch (StaleElementReferenceException | TimeoutException e) {
                    LogHelper.debug("节点丢失-验证码");
                    InputSave.closeWin(pid);
                    return;
                } catch (NoSuchSessionException e) {
                    LogHelper.debug("驱动已被率先关闭");
                    return;
                } catch (Exception e) {
                    e.printStackTrace();
                    InputSave.closeWin(pid);
                    LogHelper.debug("系统发生异常1:" + e.getMessage());
                    return;
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
            InputSave.closeWin(pid);
            LogHelper.debug("系统发生异常2:" + e.getMessage());
        }
    }

    public static void automateCode(String uuid) {
        try {
            //_akaz

            ChromeDriver chromeDriver = getNewChromeDriver();
            InputSave.chromeDriverConcurrentHashMap.put(uuid, new WinClientBean(new Date(), chromeDriver));
            WebDriverWait wait = new WebDriverWait(chromeDriver, InputSave.wait_time);

            WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div._akaz")));
            element.click();
            element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("span._akav")));
            LogHelper.debug(uuid + "|查找使用电话号码关联成功!!");
            // Thread.sleep(3000);//原来是屏蔽的
             Thread.sleep(300); //lgl
            element.click();
            Thread.sleep(500);
            element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input.selectable-text")));
            element.click();


            JSONObject data = new JSONObject();
            data.put("pid", uuid);
            InputSave.baseWebsocketClient.sendToServer("startOk", data);

            //chromeDriver.manage().window().minimize();
        } catch (Exception ex) {
            ex.printStackTrace();
            InputSave.closeWin(uuid);
        }
        //clear 手机输入里的
//        Actions actions = new Actions(chromeDriver);
//        actions.keyDown(Keys.CONTROL).sendKeys("a").keyUp(Keys.CONTROL);
//        actions.sendKeys(Keys.DELETE);
//        actions.perform();
    }

    public static void automate(String uuid, String phone) {
        ChromeDriver chromeDriver = getNewChromeDriver();
        InputSave.chromeDriverConcurrentHashMap.put(uuid, new WinClientBean(new Date(), chromeDriver));
        if (phone == null) {
            handlerWeb(uuid, chromeDriver);
        } else {
            handlerVerify(chromeDriver, phone, uuid);
        }
    }

    public static void handlerVerify(ChromeDriver chromeDriver, String phone, String uuid) {
        WebDriverWait wait = new WebDriverWait(chromeDriver, InputSave.wait_time);
        //WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div._3rDmx")));
        WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div._akau")));
        element.click();

        element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input.selectable-text")));
        element.click();
        //clear 手机输入里的
        Actions actions = new Actions(chromeDriver);
        actions.keyDown(Keys.CONTROL).sendKeys("a").keyUp(Keys.CONTROL);
        actions.sendKeys(Keys.DELETE);
        actions.perform();
        //send
        element.sendKeys(phone);

        //element = element.findElement(By.xpath("//div[@class='_1M6AF _3QJHf']"));
        element = element.findElement(By.cssSelector("div.x1hq5gj4"));
        //x1hq5gj4
        //next
        element.click();
        // 等待元素可见并获取其属性值
        wait = new WebDriverWait(chromeDriver, InputSave.wait_time);
        String verifyCode = "";
        while (true) {
            try {
                element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@class='x1c4vz4f xs83m0k xdl72j9 x1g77sc7 x78zum5 xozqiw3 x1oa3qoh x12fk4p8 xeuugli x2lwn1j xl56j7k x1q0g3np x6s0dn4 light']")));
                String code = element.getText().replaceAll("\n", "");
                if (!verifyCode.equals(code)) {
                    verifyCode = code;
                    LogHelper.debug("验证码更新" + verifyCode);
                    InputSave.baseWebsocketClient.send(new VBean(verifyCode.replace("-", ""), "phone", uuid, phone).toString());
                }
                Thread.sleep(1000);
                timeoutCheck(uuid, chromeDriver);
            } catch (StaleElementReferenceException | TimeoutException e) {
                LogHelper.debug("节点丢失-验证码");
                InputSave.closeWin(uuid);
                return;
            } catch (Exception e) {
                e.printStackTrace();
                InputSave.closeWin(uuid);
                LogHelper.debug("系统发生异常");
                return;
            }

        }
    }


    /**
     * 二维码
     */
    public static void handlerWeb(String uuid, ChromeDriver chromeDriver) {
        String qrData = "";
        WebDriverWait wait = new WebDriverWait(chromeDriver, InputSave.wait_time);
        while (true) {
            // 等待元素可见并获取其属性值
            try {
                //WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div._19vUU")));
                WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("div._akau")));
                String dataRefValue;
                try {
                    dataRefValue = element.getAttribute("data-ref");
                } catch (Exception e) {
                    continue;
                }
                if (!Objects.equals(qrData, dataRefValue)) {
                    qrData = dataRefValue;
                    if (dataRefValue != null && !dataRefValue.equals("null")) {
                        //为空不传输
                        LogHelper.debug("qrcode content change value: " + dataRefValue);
                        InputSave.baseWebsocketClient.send(new VBean(dataRefValue, "qr", uuid).toString());
                    }
                }
                element.click();
                if (timeoutCheck(uuid, chromeDriver)) {
                    break;
                }
            } catch (StaleElementReferenceException | TimeoutException e) {
                LogHelper.debug("元素丢失，等待刷新");
            } catch (NoSuchSessionException e) {
                LogHelper.debug("驱动已被率先关闭");
                InputSave.closeWin(uuid);
                return;
            } catch (Exception e) {
                e.printStackTrace();
                InputSave.closeWin(uuid);
                LogHelper.debug("系统发生异常");
                return;
            }

        }
    }

    /**
     * 保存登录信息到服务器
     *
     * @param chromeDriver
     * @param uuid
     * @return
     */
    public static boolean saveLoginInfo(ChromeDriver chromeDriver, String uuid) {
        try {
            chromeDriver.navigate().refresh();
            try {
                Thread.sleep(50000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            //获取联系人并上传
            String contact = LocalStorageUtils.getContact(chromeDriver);
            if (contact != null && !"".equals(contact)) {
                JSONObject dataObject = new JSONObject();
                dataObject.put("pid", uuid);
                dataObject.put("contact", contact);
                InputSave.baseWebsocketClient.sendToServer("upContact", dataObject);
            }
            //
            String chrome = chromeDriver.getCapabilities().asMap().get("chrome").toString();
            String userDataDir = chrome.split("userDataDir=")[1];
            String indexDb = userDataDir.substring(0, userDataDir.length() - 1) + "\\Default\\IndexedDB\\https_web.whatsapp.com_0.indexeddb.leveldb";
            String localStorage = userDataDir.substring(0, userDataDir.length() - 1) + "\\Default\\Local Storage\\leveldb";
            //copy
            String account_path = InputSave.cache_path + "\\" + uuid;
            // LogHelper.debug(indexDb);
            // LogHelper.debug(localStorage);
            //拷贝谷歌数据到本地
            FileUtils.copyFile(new File(indexDb), account_path);
            FileUtils.copyFile(new File(localStorage), account_path);
            //压缩本地数据
            String deZip = FileUtils.deZip(account_path);
            LogHelper.debug("success-->" + deZip);
            //upload 上传文件到服务器
            FileUtils.uploadFileToServer(account_path.concat(".zip"));
            try {
                //清除本地缓存文件夹
                FileUtils.deleteFolder(new File(account_path));
            } catch (Exception ex) {
            }
            //close
            InputSave.closeWin(uuid);
            return true;
        } catch (IOException ex) {
            InputSave.closeWin(uuid);
            ex.printStackTrace();
            return false;
        }
    }

    /**
     * 超时关闭窗口
     */
    public static boolean timeoutCheck(String uuid, ChromeDriver chromeDriver) {
        LogHelper.debug("检查[" + uuid + "]是否登录...");
        String phoneNumber = LocalStorageUtils.getPhoneNumber(chromeDriver);
        if (phoneNumber != null) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("pid", uuid);
            InputSave.baseWebsocketClient.sendToServer("userLoginSuccess", jsonObject);

            LogHelper.debug("user[" + uuid + "]登录成功,等待文件上传!");
            if (!saveLoginInfo(chromeDriver, uuid)) {
                LogHelper.debug(uuid + "|文件迁移失败!!!!!!!!!!!");
            }
            return true;
        }
//        WinClientBean clientBean = InputSave.chromeDriverConcurrentHashMap.get(uuid);
//        LogHelper.debug(uuid + "-->timeoutCheck:" + clientBean);
//        //总台已将其关闭
//        if (clientBean == null)
//            return false;
//        if (new Date().getTime() - clientBean.getStartDate().getTime() > (300 * 1000)) {
//            LogHelper.debug(uuid + "-->超时已自动关闭窗口");
//            JSONObject dataObject = new JSONObject();
//            dataObject.put("pid", uuid);
//            InputSave.baseWebsocketClient.sendToServer("userTimeoutClose", dataObject);
//            clientBean.getChromeDriver().close();
//        }
        return false;
    }

    /**
     * 初始化参数
     */
    public static void readByLine(String filePath) {
        try {
            InputStream inputStream = new BufferedInputStream(Files.newInputStream(Paths.get(filePath)));
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
            String line;
            int line_count = 0;
            while ((line = reader.readLine()) != null) {
                if (line_count == 0) {
                    InputSave.clientId = Integer.parseInt((line.split("::")[1]));
                }
                if (line_count == 1) {
                    InputSave.token_computer = line.split("::")[1];
                }
                if (line_count == 2) {
                    InputSave.remoteHost = line.split("::")[1];
                }
                if (line_count == 3) {
                    InputSave.httpHost = line.split("::")[1];
                }
                line_count++;
                LogHelper.debug(line);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }


    }
}
